package com.whz.governance.http.feign;

import com.whz.generic.json.JacksonUtils;
import feign.Logger;
import feign.RequestInterceptor;
import feign.codec.Decoder;
import feign.codec.Encoder;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.lang.NonNull;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author whz
 */
@val
@Slf4j
@Configuration
public class FeignConfiguration {

    /**
     * carry all headers through next service
     */
    @Bean
    public RequestInterceptor headerInterceptor() {
        return requestTemplate -> {
            RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
            if (!(attributes instanceof ServletRequestAttributes)) {
                return;
            }
            HttpServletRequest request = ((ServletRequestAttributes) attributes).getRequest();
            for (String name : HttpAccessUtils.getAccessHeaders()) {
                val value = request.getHeader(name);
                if (StringUtils.isEmpty(value)) {
                    continue;
                }
                log.debug("header[{} = {}] will access through next service", name, value);
                requestTemplate.header(name, value);
            }
        };
    }

    @Bean
    @ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev")
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }

    @Bean
    @ConditionalOnMissingBean(MappingJackson2HttpMessageConverter.class)
    @ConditionalOnProperty(name = "generic.openfeign.jackson.enable", havingValue = "true", matchIfMissing = true)
    public Encoder feignJacksonEncoder() {
        return new SpringEncoder(feignJacksonJsonHttpMessageConverter());
    }

    @Bean
    @ConditionalOnMissingBean(MappingJackson2HttpMessageConverter.class)
    @ConditionalOnProperty(name = "generic.openfeign.jackson.enable", havingValue = "true", matchIfMissing = true)
    public Decoder feignJacksonDecoder() {
        return new SpringDecoder(feignJacksonJsonHttpMessageConverter());
    }

    private static ObjectFactory<HttpMessageConverters> feignJacksonJsonHttpMessageConverter() {
        return FeignConfiguration::getJacksonHttpMessageConverters;
    }

    @NonNull
    public static HttpMessageConverters getJacksonHttpMessageConverters() {
        return new HttpMessageConverters(
                new MappingJackson2HttpMessageConverter(JacksonUtils.createDefaultObjectMapper()));
    }
}